package com.sync.data.job.user;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.sync.data.common.util.PassUtil;
import com.sync.data.common.util.SetValueUtils;
import com.sync.data.ievent.entity.IeventSysUser;
import com.sync.data.ievent.repository.IeventSysUserRepository;
import com.sync.data.mce.entity.MceSysUser;
import com.sync.data.mce.repository.MceSysUserRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.NonUniqueResultException;
import org.hibernate.exception.ConstraintViolationException;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.data.RepositoryItemReader;
import org.springframework.batch.item.database.JpaItemWriter;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.transaction.PlatformTransactionManager;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Configuration
//@EnableBatchProcessing
@Order(1)
@RequiredArgsConstructor
@Slf4j
public class SysUserSyncBatchJob {

    private final JobBuilderFactory jobBuilderFactory;

    private final StepBuilderFactory stepBuilderFactory;

    private final MceSysUserRepository mceSysUserRepository;

    private final IeventSysUserRepository ieventSysUserRepository;

    private final PlatformTransactionManager transactionManagerIevent;

    private final JpaItemWriter<IeventSysUser> ieventSysUserJpaItemWriter;

    private final Step syncEmployeeStep;
    private final Step syncPositionEmployeeStep;
    private final Step syncPositionsStep;

    // 批处理大小
    private static final int CHUNK_SIZE = 100;

    @Bean
    public Job userSyncJob() {
        return jobBuilderFactory.get("userSyncJob")
                .incrementer(new RunIdIncrementer())
                //.start(prepareWorkNoSetStep())
                .start(syncUsersStep())
                .next(syncEmployeeStep)
                .next(syncPositionsStep)
                .next(syncPositionEmployeeStep)
                .build();
    }

    public Step prepareWorkNoSetStep() {
        return stepBuilderFactory.get("prepareWorkNoSetStep")
                .tasklet((contribution, chunkContext) -> {
                    Set<String> workNoSet = ieventSysUserRepository.findAllWorkNoSet();
                    chunkContext.getStepContext()
                            .getStepExecution()
                            .getJobExecution()
                            .getExecutionContext()
                            .put("workNoSet", workNoSet);

                    return RepeatStatus.FINISHED;
                })
                .build();
    }

    public Step syncUsersStep() {
        return stepBuilderFactory.get("syncUsersStep")
                .<MceSysUser, IeventSysUser>chunk(CHUNK_SIZE)
                .reader(mceUserReader())
                .processor(userSyncProcessor())
                .writer(ieventSysUserJpaItemWriter)
                .faultTolerant()
                .skipLimit(1000)
                .skip(DataIntegrityViolationException.class)
                .skip(ConstraintViolationException.class)
                .skip(IncorrectResultSizeDataAccessException.class)
                .skip(NonUniqueResultException.class)
                .transactionManager(transactionManagerIevent)
                .build();
    }

//    public Step syncUsersStep() {
//        return stepBuilderFactory.get("syncUsersStep")
//                .<List<MceSysUser>, List<IeventSysUser>>chunk(1) // 每次处理一个批次
//                .reader(batchMceUserReader())
//                .processor(batchUserSyncProcessor())
//                .writer(batchIeventSysUserWriter())
//                .faultTolerant()
//                .skipLimit(1000)
//                .skip(DataIntegrityViolationException.class)
//                .skip(ConstraintViolationException.class)
//                .skip(IncorrectResultSizeDataAccessException.class)
//                .skip(NonUniqueResultException.class)
//                .transactionManager(transactionManagerIevent)
//                .build();
//    }


    public ItemReader<MceSysUser> mceUserReader() {
        RepositoryItemReader<MceSysUser> reader = new RepositoryItemReader<>();
        reader.setRepository(mceSysUserRepository);
        reader.setMethodName("findAll");
        reader.setSort(Collections.singletonMap("id", Sort.Direction.ASC));
        reader.setPageSize(CHUNK_SIZE);
        return reader;
    }

    public ItemProcessor<MceSysUser, IeventSysUser> userSyncProcessor() {
        return mceUser -> {
            if (StrUtil.equals(mceUser.getWorkNo(), "00000001")) return null;
            try {
                IeventSysUser ieventUser = ieventSysUserRepository.findByUsername(mceUser.getUsername()).orElse(new IeventSysUser());
                if (!StrUtil.equals(ieventUser.getId(), mceUser.getId())) {
                    ieventSysUserRepository.delete(ieventUser);
                    ieventSysUserRepository.flush();
                    ieventUser = new IeventSysUser();
                }
                BeanUtil.copyProperties(mceUser, ieventUser, CopyOptions.create().setIgnoreNullValue(true).setIgnoreProperties("createTime"));
                ieventUser.setStatusField("1");
                ieventUser.setDelFlag(0);
                SetValueUtils.setIfNotEmpty(mceUser::getProfileField, ieventUser::setProfileField, "ccpr9");
                if (StrUtil.isBlank(mceUser.getPassword()) || StrUtil.equals(mceUser.getPassword(), "1")) {
                    String salt = RandomUtil.randomString(8);
                    String encryptPassword = PassUtil.encrypt(ieventUser.getUsername(), "123456", salt);
                    ieventUser.setPassword(encryptPassword);
                    ieventUser.setSalt(salt);
                }
                return ieventUser;
            } catch (NonUniqueResultException e) {
                log.error("=========>workNo{}", mceUser.getWorkNo());
                throw e;
            }
        };
    }


    public ItemReader<List<MceSysUser>> batchMceUserReader() {
        return new RepositoryItemReader<List<MceSysUser>>() {
            private int page = 0;

            @Override
            public List<MceSysUser> read() {
                Pageable pageable = PageRequest.of(page++, CHUNK_SIZE, Sort.by("id").ascending());
                Page<MceSysUser> userPage = mceSysUserRepository.findAll(pageable);
                return userPage.hasContent() ? userPage.getContent() : null;
            }
        };
    }

    public ItemProcessor<List<MceSysUser>, List<IeventSysUser>> batchUserSyncProcessor() {
        return mceUsers -> {
            // 过滤掉特定用户
            List<MceSysUser> filteredUsers = mceUsers.stream()
                    .filter(user -> !StrUtil.equals(user.getWorkNo(), "00000001"))
                    .collect(Collectors.toList());

            // 提取工号列表
            List<String> workNos = filteredUsers.stream()
                    .map(MceSysUser::getWorkNo)
                    .collect(Collectors.toList());

            // 批量查询现有用户
            List<IeventSysUser> existingUsers = ieventSysUserRepository.findByWorkNoIn(workNos);
            Map<String, IeventSysUser> existingUserMap = existingUsers.stream()
                    .collect(Collectors.toMap(IeventSysUser::getWorkNo, Function.identity(), (k1, k2) -> k2));

            // 处理用户转换
            List<IeventSysUser> result = new ArrayList<>();
            for (MceSysUser mceUser : filteredUsers) {
                IeventSysUser ieventUser = existingUserMap.getOrDefault(mceUser.getWorkNo(), new IeventSysUser());
                BeanUtil.copyProperties(mceUser, ieventUser,
                        CopyOptions.create().setIgnoreNullValue(true).setIgnoreProperties("id", "createTime"));

//                ieventUser.setStatusField("1");
                ieventUser.setDelFlag(0);
                SetValueUtils.setIfNotEmpty(mceUser::getProfileField, ieventUser::setProfileField, "ccpr9");

                if (StrUtil.isBlank(mceUser.getPassword()) || StrUtil.equals(mceUser.getPassword(), "1")) {
                    String salt = RandomUtil.randomString(8);
                    String encryptPassword = PassUtil.encrypt(ieventUser.getUsername(), "123456", salt);
                    ieventUser.setPassword(encryptPassword);
                    ieventUser.setSalt(salt);
                }

                result.add(ieventUser);
            }

            return result;
        };
    }

    public ItemWriter<List<IeventSysUser>> batchIeventSysUserWriter() {
        return chunks -> {
            for (List<IeventSysUser> users : chunks) {
                ieventSysUserRepository.saveAll(users);
            }
        };
    }
}